<?php
/**
 * RedCross Application
 *
 * @copyright Copyright (c) 2010, Kristian Stokke Tryggestad, Rune Vikestad, Andreas Flaten Wist, Simen Nicolai Echholt, Ole Henrik Jahren
 */

/**
 * Member Service class for communication between controllers and persistent storage
 *
*/
class Core_Service_Member extends RedCross_Service_ServiceAbstract
{
  /**
   * Constant value to return if one tries to add a phone number
   * that is already registered to the member
   * @var string
   */
  const PHONE_DUPLICATE = 'PHONE_DUPLICATE';

  /**
   * Constant value to return if one tries to add an email address
   * that is already registered in the system
   * @var string
   */
  const EMAIL_DUPLICATE = 'EMAIL_DUPLICATE';

  /**
   * Constant value to return if one tries to add a passive message
   * with an invalid date
   */
  const INVALID_PASSIVE_START_DATE = 1001;

  const INVALID_PASSIVE_END_DATE = 1002;

    /**
     * Constructor
     * @param Core_Gateway_User $gateway
     */
    public function __construct(Core_Gateway_Member $gateway)
    {
        parent::__construct($gateway, 'Core_Model_Member');
    }

    /**
     * Register a new member with the application
     *
     * @param array $data
     * @return boolean
     */
    public function create(array $data)
    {
        $this->checkAcl('create');

        $member = $this->getGateway()->fetchByEmail($data['email']);
        if ($member) {
          return false;
        }

        $model = new Core_Model_Member();
        $model->first_name = $data['first_name'];
        $model->last_name = $data['last_name'];
        $model->address = $data['address'];
        $model->postal_id = $data['postal_code'];
        $model->redcross_id = $data['redcross_id'];
        $model->emails[0]->address = $data['email'];
        $model->emails[0]->is_main = 1;
        $model->Phonenumbers[0]->number = $data['phone'];
        $model->Phonenumbers[0]->phonetype_id = $data['phonetype'];

        unset($data);

        $date = new RedCross_Date();
    $model->joined_date = $date->export();

        return $this->save($model);
    }

    public function delete($memberId)
    {
        $this->checkAcl('delete');
        return $this->getGateway()->delete($memberId);
    }

    public function setComment($memberId, array $data)
    {
        $member = $this->getGateway()->fetch((int) $memberId);
        if (!$member)
        {
          return false;
        }

    if($data['comment'] != null && $data['comment'] !== '') {
        $member->comment = $data['comment'];
    } else {
        $member->comment = null;
    }

        return $this->save($member);
    }

    public function editPersonalia($memberId, array $data)
    {
        $member = $this->getGateway()->fetch((int) $memberId);
        if (!$member)
        {
          return false;
        }

    $member->first_name = $data['first_name'];
    $member->last_name = $data['last_name'];
    if($data['address'] != null && $data['address'] !== '') {
      $member->address = $data['address'];
    } else {
      $member->address = null;
    }

    if($data['address_2'] != null && $data['address_2'] !== '') {
      $member->address_2 = $data['address_2'];
    } else {
      $member->address_2 = null;
    }

    if($data['postal_code'] != null && $data['postal_code'] !== '') {
        $member->postal_id = (int) $data['postal_code'];
    } else {
        $member->postal_id = null;
    }

    if($data['redcross_id'] != null && $data['redcross_id'] !== '') {
        $member->redcross_id = $data['redcross_id'];
    } else {
        $member->redcross_id = null;
    }

        return $this->save($member);
    }

    public function fetchWithPhoneAndEmail($id)
    {
      return $this->_gateway->fetchWithPhoneAndEmail($id);
    }
    public function fetchByEmail($email)
    {
      return $this->getGateway()->fetchByEmail($email);
    }

    public function fetchById($id)
    {
        return $this->getGateway()->fetchById($id);
    }

    public function fetchAllAndJoin($paginate = false)
    {
        $this->checkAcl('fetchAll');
        return $this->getGateway()->fetchAllAndJoin($paginate);
    }

    public function fetchAllActive($paginate = false)
    {
        $this->checkAcl('fetchAll');
        return $this->getGateway()->fetchAllActive($paginate);
    }

    public function fetchAllInActive($paginate = false)
    {
        $this->checkAcl('fetchAll');
        return $this->getGateway()->fetchAllInActive($paginate);
    }

    public function fetchAllOrderByLastnameInactiveLast($paginate = false)
    {
        return $this->getGateway()->fetchAllOrderByLastnameInactiveLast($paginate);
    }

    public function fetchByIdJoinOnCourse($id)
    {
      return $this->getGateway()->fetchByIdJoinOnCourse($id);
    }

    public function fetchByIdJoinOnAccess($id)
    {
      return $this->getGateway()->fetchByIdJoinOnAccess($id);
    }
   public function fetchEligibleForRole($shiftRole, $options = array())
    {
      return $this->getGateway()->fetchEligibleForRole($shiftRole, $options);
    }

    public function addPhone($memberId, array $data)
    {
        $member = $this->fetch((int) $memberId);
        if (!$member) {
          return false;
        }

        $phonenumbers = $member->Phonenumbers;
        foreach($phonenumbers as $phone)
        {
          if ($phone->number === $data['phone']) {
                return self::PHONE_DUPLICATE;
          }
        }

        $phone = new Core_Model_Phone();
        $phone->phonetype_id = $data['phonetype'];
        $phone->member_id = $memberId;
        $phone->number = $data['phone'];
        return $phone->save() !== false;
    }

    public function addEmail($memberId, array $data)
    {
        $member = $this->fetch((int) $memberId);
        if (!$member)
        {
          return false;
        }
        $memberByEmail = $this->fetchByEmail($data['email']);
        if ($memberByEmail)
        {
          return self::EMAIL_DUPLICATE;
        }
        $mail = new Core_Model_Email();
        $mail->member_id = $data['id'];
        $mail->address = $data['email'];
        $mail->is_main = 0;
        $member->emails[] = $mail;
        return $this->save($member) != false;
    }

    public function addNextOfKin($memberId, array $data)
    {
        $member = $this->fetch((int) $memberId);
        if (!$member) return false;

        $nok = new Core_Model_NextOfKin();
        $nok->first_name = $data['first_name'];
        $nok->last_name = $data['last_name'];
        $nok->phone_number = $data['phone_number'];
        $member->NextOfKin[] = $nok;
        return $this->save($member) != false;
    }

    public function togglePermanentPassive($memberId, array $data)
    {
        $this->checkAcl('togglePermanentPassive');
    $memberId = (int) $memberId;
    if ($this->isPermanentPassive($memberId)) {
      return $this->getGateway()->removePermanentPassive($memberId);
    } else {
            return $this->getGateway()->addPermanentPassive($memberId, $data['comment']);
    }
    }

    /*
     * Returns an array with passive messages between the given dates,
     * or all passive messages if the parameters are not specified.
     *
     */
    public function getPassiveMessages($member_id, $from_date = null, $to_date = null)
    {
      return $this->_gateway->getPassiveMessages($member_id,$from_date, $to_date);
    }

    public function addPassiveMessage(array $data)
    {
      $member = $this->fetch((int) $data['member_id']);
    if (!$member)
    {
      return false;
    }
    if (!Zend_Date::isDate($data['from_date'], Core_Form_Passive_Add::DATE_FORMAT))
    {
      return self::INVALID_PASSIVE_START_DATE;
    }
    $earliestDate = new RedCross_Date(); //The earliest date a new message can be added on
    $earliestDate->add(3, Zend_Date::WEEK);
    $fromDate = new RedCross_Date($data['from_date'], Core_Form_Passive_Add::DATE_FORMAT);
    if ($earliestDate->compareDate($fromDate) == 1)
    {
      return self::INVALID_PASSIVE_START_DATE;
    }
    if (!empty($data['to_date']))
    {
      if (!Zend_Date::isDate($data['to_date'], Core_Form_Passive_Add::DATE_FORMAT))
      {
        return self::INVALID_PASSIVE_END_DATE;
      }
      $toDate = new RedCross_Date($data['to_date'], Core_Form_Passive_Add::DATE_FORMAT);
      if ($earliestDate->compareDate($toDate) == 1)
      {
        return self::INVALID_PASSIVE_END_DATE;
      }
    } else
    {
      $toDate = new RedCross_Date($fromDate);
    }
    foreach (array($fromDate,$toDate) as $d)
    {
      $d->setHour(0);
      $d->setMinute(0);
      $d->setSecond(0);
    }

    $memberId = $member->id;

        // Database transaction
    $manager = Doctrine_Manager::getInstance();
    $connection = $manager->getCurrentConnection();
    $connection->beginTransaction();

    $this->removePassiveMessages($memberId, $fromDate, $toDate);
    while($fromDate->compareDate($toDate) < 1)
    {
        $passiveMessage = new Core_Model_Passive();
        $passiveMessage->date = $fromDate->export();
        $passiveMessage->member_id = $memberId;
        $passiveMessage->save();
        $fromDate->add(1, Zend_Date::DAY);
    }

    try {
        $connection->commit();
        return true;
    } catch (Doctrine_Exception $e) {
        $connection->rollback();
        return false;
    }
    }

    public function removeAccess($memberId, array $data) {
        $this->checkAcl('editAccess');
        $member = $this->fetchByIdJoinOnAccess((int) $memberId);
        if (!$member) { throw new RedCross_Exception_NotFound("Could not find member"); }

        $accessService = RedCross_Factory::getService('Core_Service_Access');
        $access = $accessService->fetch((int) $data['access']);
        if (!$access) { throw new RedCross_Exception_NotFound("Could not find access area"); }

        $memberAccessService = RedCross_Factory::getService('Core_Service_MemberAccess');
        $memberAccessService->removeAccess($memberId, $access);
        return $member;
    }

    public function addPayment($memberId, $year) {
        // TODO: ACL ACL ACL
        // $this->checkAcl('editFee');
        $member = $this->fetch((int) $memberId);
        if (!$member) { throw new RedCross_Exception_NotFound("Could not find member"); }

        $year = (int)$year;

        $payment = new Core_Model_MembershipFee();
        $payment->member_id = $member->id;
        $payment->year = $year;
        $payment->save();

        return $payment;
    }

    public function removePayment($memberId, $year) {
        $member = $this->fetch((int) $memberId);
        if (!$member) { throw new RedCross_Exception_NotFound("Could not find member"); }

            $feeService = RedCross_Factory::getService('Core_Service_MembershipFee');
            $year = (int)$year;

            $payments = $feeService->fetchByMemberIdAndYear($member->id, $year);
            $count = $payments->delete();

            return $count;
    }
    

    public function addAccess($memberId, array $data) {
        $this->checkAcl('editAccess');
        $member = $this->fetchByIdJoinOnAccess((int) $memberId);
        if (!$member) { throw new RedCross_Exception_NotFound("Could not find member"); }

        $accessService = RedCross_Factory::getService('Core_Service_Access');
        $access = $accessService->fetch((int) $data['access']);
        if (!$access) { throw new RedCross_Exception_NotFound("Could not find access area"); }


        $memberAccessService = RedCross_Factory::getService('Core_Service_MemberAccess');
        $accessId = (int)$data['access'];
        $recordExists = $memberAccessService->checkIfExists($memberId, $accessId);
        if ($recordExists) {
            $memberAccessService->updateRecord($memberId, $accessId);
        } else {
            $date = new RedCross_Date();
            $memberAccess = new Core_Model_MemberAccess();
            $memberAccess->access_id = $accessId;
            $memberAccess->member_id = $member->id;
            $memberAccess->gained_access_date = $date->export();
            $memberAccess->lost_access_date = null;
            $memberAccess->save();
        }
        return $member;
    }

    public function addCourse($memberId, array $data)
    {
        $this->checkAcl('editCourses');

        $member = $this->fetchByIdJoinOnCourse((int) $memberId);
        if (!$member)
        {
        return false;
        }

        $courseService = RedCross_Factory::getService('Core_Service_Course');
        $course = $courseService->fetch((int) $data['course']);
        if (!$course)
        {
        return false;
        }

        //If the course is already registered to the user, delete the old entry and add the new one
        //WARNING: If you change this behaviour, you have to change how the "reset expiration date"
        //link in the admin/member/courses.phtml page works, because that link uses this method.
        $this->removeCourse($memberId, $data['course']);

        $date = new RedCross_Date();

        if (isset ($data['course_date']))
        {
            $temp = $data['course_date'] . ' 00:00';
            $date = new RedCross_Date($temp, RedCross_Date::NO_DATETIME_FMT);
        }
        else if  (isset ($data['competence_date']))
        {
            $temp = $data['competence_date'] . ' 00:00';
            $date = new RedCross_Date($temp, RedCross_Date::NO_DATETIME_FMT);
        }

        $memberCourse = new Core_Model_MemberCourse();
        $memberCourse->course_id = $data['course'];
        $memberCourse->member_id = $member->id;
        $memberCourse->added_date = $date->export();

        if (!is_null($course->months_valid))
        {
            $expiresDate = new RedCross_Date($date);
            $expiresDate->add($course->months_valid, Zend_Date::MONTH);
            $memberCourse->expires_date = $expiresDate->export();
        } else
        {
            $memberCourse->expires_date = null;
        }
        $member->MemberCourse[] = $memberCourse;
        $memberCourse->save();
        return $member;
    }

    public function removeCourse($member_id, $course_id)
    {
        $this->checkAcl('editCourses');

        $member_id = (int) $member_id;
        $course_id = (int) $course_id;

        $member = $this->fetch($member_id);
        if (!$member)
        {
            return false;
        }

        $q = Doctrine_Query::create()
            ->delete('Core_Model_MemberCourse mc')
            ->where('mc.member_id = ? AND mc.course_id = ?', array($member_id, $course_id))
            ->execute();

        return $q != false;
    }

    public function isPermanentPassive($memberId)
    {
        return $this->getGateway()->isPermanentPassive($memberId);
    }

    private function removePermanentPassive($memberId)
    {
        return $this->getGateway()->removePermanentPassive($memberId);
    }

    private function addPermanentPassive($memberId, $comment)
    {
        return $this->getGateway()->addPermanentPassive($memberId, $comment);
    }

    private function removePassiveMessages($memberId, $fromDate, $toDate)
    {
  return $this->getGateway()->removePassiveMessages($memberId, $fromDate, $toDate);
    }

    public function fetchMembersWithCourse($courseId)
    {
        return $this->getGateway()->fetchMembersWithCourse($courseId);
    }

    public function fetchMembersWithoutCourse($courseId)
    {
        return $this->getGateway()->fetchMembersWithoutCourse($courseId);
    }

    public function fetchByUsername($username)
    {
        return $this->getGateway()->fetchByUsername($username);
    }
}
